package com.hd.controller.login;

import com.hd.commons.annotation.LogAnnotation;
import com.hd.commons.shiro.PasswordHash;
import com.hd.commons.shiro.ShiroUser;
import com.hd.commons.shiro.captcha.DreamCaptcha;
import com.hd.commons.shiro.filter.ForceLogoutFilter;
import com.hd.controller.base.BaseController;
import com.hd.entity.enums.OperatorTypeEnum;
import com.hd.entity.enums.PushMsgTypeEnum;
import com.hd.entity.netty.PushMsg;
import com.hd.entity.sys.Log;
import com.hd.netty.constant.Constant;
import com.hd.netty.server.WebSocketServerHandler;
import com.hd.service.CommonService;
import com.hd.service.sys.LogService;
import com.hd.service.sys.UserService;
import com.hd.util.JsonUtil;
import com.hd.util.ShiroAuthUtil;
import com.hd.util.StringUtils;
import io.netty.channel.ChannelHandlerContext;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.DisabledAccountException;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.session.Session;
import org.apache.shiro.session.mgt.eis.SessionDAO;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.subject.support.DefaultSubjectContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.*;

/**
 * @author hzhh123
 * @time 2018年1月23日下午5:12:45
 **/
@Controller
public class LoginController extends BaseController {
    @Autowired private LogService logService;
    @Autowired
    private DreamCaptcha dreamCaptcha;
    @Autowired
    private UserService userService;
    @Autowired
    private PasswordHash passwordHash;
    @Autowired
    private CommonService commonService;
    @Autowired
    private SessionDAO sessionDAO;
//    @Autowired
//    private RedisSessionDAO redisSessionDAO;

    /**
     * 首页
     *
     * @return
     */
    @RequestMapping("/")
    public String index() {
        return "redirect:/index";
    }

    /**
     * 首页
     *
     * @param model
     * @return
     */
    @RequestMapping("/index")
    public String index(Model model) {
        if (SecurityUtils.getSubject().isAuthenticated()) {
            model.addAttribute("sessionId", SecurityUtils.getSubject().getSession().getId());
            //限制用户只能在一个地方登录
            limitLogin();
            //limitLogin2();
        }
        return "jsp/index";
    }

    /**
     * GET 登录
     * @return {String}
     */
    @RequestMapping("/login")
    /*@CsrfToken(create = true)*/
    public String login(/* HttpSession session */HttpServletRequest request, Model model) {
        logger.info("GET请求登录");
        if (SecurityUtils.getSubject().isAuthenticated()) {
            return "redirect:/index";
        } else {
            if (request.getParameter("forceLogout") != null) {
                // model.addAttribute("error", "您已经被管理员强制退出，请重新登录");
            }
            //session.setAttribute("encryption_key", UUID.randomUUID().toString());
        }
        return "jsp/login";
    }

    /**
     * POST 登录 shiro 写法
     * @param username 用户名
     * @param password 密码
     * @return {Object}
     */
    /*  @CsrfToken(remove = true)*/
    @RequestMapping(value = "/login", method = RequestMethod.POST)
    @ResponseBody
    public Object loginPost(HttpServletRequest request, HttpServletResponse response,
                            String username, String password, String captcha,
                            @RequestParam(value = "rememberMe", defaultValue = "0") Integer rememberMe) throws Exception {
        logger.info("POST请求登录");
        // 改为全部抛出异常，避免ajax csrf token被刷新
        if (StringUtils.isBlank(username)) {
            throw new RuntimeException("用户名不能为空");
        }
        if (StringUtils.isBlank(password)) {
            throw new RuntimeException("密码不能为空");
        }
        if (StringUtils.isBlank(captcha)) {
            throw new RuntimeException("验证码不能为空");
        }
        if (!dreamCaptcha.validate(request, response, captcha)) {
            throw new RuntimeException("验证码错误");
        }


//        HttpSession session = request.getSession();
//        String key = (String) session.getAttribute("encryption_key");
//        password = DesUtil.decrypt(password, key);
//        username = DesUtil.decrypt(username, key);
        Subject user = SecurityUtils.getSubject();
        UsernamePasswordToken token = new UsernamePasswordToken(username, password);
        // 设置记住密码
        //token.setRememberMe(1 == rememberMe);
        token.setRememberMe(true);
        try {
            user.login(token);
            logger.info("sessionId={}", user.getSession().getId());
            logger.info("登录成功！");
            Log sysLog=new Log();
            sysLog.setUsername(username);
            sysLog.setCreateTime(new Date());
            sysLog.setOptContent("登录成功");
            sysLog.setDesc("登录成功");
            sysLog.setOptType(OperatorTypeEnum.LOGIN.toString());
            if (request != null) {
                sysLog.setClientIp(request.getRemoteAddr());
            }
            logService.save(sysLog);
            return renderSuccess("登录成功！");
        } catch (UnknownAccountException e) {
            throw new RuntimeException("账号不存在！", e);
        } catch (DisabledAccountException e) {
            throw new RuntimeException("账号未启用！", e);
        } catch (IncorrectCredentialsException e) {
            throw new RuntimeException("密码错误！", e);
        } catch (Throwable e) {
            throw new RuntimeException(e.getMessage(), e);
        }
    }

    /**
     * 限制用户多地登录，仅能在一个地方登录
     */
    private void limitLogin() {
        String sessionId = (String) SecurityUtils.getSubject().getSession().getId();
        ShiroUser shiroUser = getShiroUser();
        String username = shiroUser.getUsername();
        Collection<Session> sessions = sessionDAO.getActiveSessions();
        List<Map<String, Object>> sessionListMap = new ArrayList<Map<String, Object>>();
        Iterator<Session> it = sessions.iterator();
        while (it.hasNext()) {
            Session session = it.next();
            System.out.println("*******************************在线用户***************************************");
            System.out.println(session.getAttribute(DefaultSubjectContext.PRINCIPALS_SESSION_KEY));
            System.out.println("******************************************************************************");
            if (username.equals(String.valueOf(session.getAttribute(DefaultSubjectContext.PRINCIPALS_SESSION_KEY)))) {
                if (!session.getId().equals(sessionId)) {
                    session.setAttribute(ForceLogoutFilter.SESSION_FORCE_LOGOUT_KEY, Boolean.TRUE);
                    //netty推送消息至web端
                    ChannelHandlerContext ctx = Constant.pushCtxMap.get(session.getId());
                    if (ctx != null) {
                        PushMsg pushMsg = new PushMsg();
                        pushMsg.setCreateTime(new Date());
                        pushMsg.setId(UUID.randomUUID().toString());
                        pushMsg.setMsg("该账户已在另外一个地方登录，本次会话强制结束");
                        pushMsg.setType(PushMsgTypeEnum.REMOTE_LOGIN.getType());
                        pushMsg.setUrl("/login?forceLogout=1");
                        WebSocketServerHandler.push(ctx, JsonUtil.toJson(pushMsg));
                        sessionDAO.delete(session);
                    }
                }
            }
        }
    }


    /**
     * redis限制用户登录
     */
//    private void limitLogin2() {
//        String sessionId = (String) SecurityUtils.getSubject().getSession().getId();
//        ShiroUser shiroUser = getShiroUser();
//        String username = shiroUser.getUsername();
//        Collection<Session> sessions = redisSessionDAO.getActiveSessions();
//        List<Map<String, Object>> sessionListMap = new ArrayList<Map<String, Object>>();
//        Iterator<Session> it = sessions.iterator();
//        while (it.hasNext()) {
//            Session session = it.next();
//            System.out.println("*******************************在线用户***************************************");
//            System.out.println(session.getAttribute(DefaultSubjectContext.PRINCIPALS_SESSION_KEY));
//            System.out.println("******************************************************************************");
//            if (username.equals(String.valueOf(session.getAttribute(DefaultSubjectContext.PRINCIPALS_SESSION_KEY)))) {
//                if (!session.getId().equals(sessionId)) {
//                    session.setAttribute(ForceLogoutFilter.SESSION_FORCE_LOGOUT_KEY, Boolean.TRUE);
//                    //netty推送消息至web端
//                    ChannelHandlerContext ctx = Constant.pushCtxMap.get(session.getId());
//                    if (ctx != null) {
//                        PushMsg pushMsg = new PushMsg();
//                        pushMsg.setCreateTime(new Date());
//                        pushMsg.setId(UUID.randomUUID().toString());
//                        pushMsg.setMsg("该账户已在另外一个地方登录，本次会话强制结束");
//                        pushMsg.setType(PushMsgTypeEnum.REMOTE_LOGIN.getType());
//                        pushMsg.setUrl("/login?forceLogout=1");
//                        WebSocketServerHandler.push(ctx, JsonUtil.toJson(pushMsg));
//                        redisSessionDAO.delete(session);
//                    }
//                }
//            }
//        }
//    }

    /**
     * 未授权
     *
     * @return {String}
     */
    @RequestMapping("/unauth")
    public String unauth() {
        if (SecurityUtils.getSubject().isAuthenticated() == false) {
            return "redirect:/login";
        }
        return "unauth";
    }

    /**
     * 退出
     *
     * @return {Result}
     */
    @LogAnnotation(value = "登出",method = OperatorTypeEnum.LOGOUT)
    @RequestMapping(value = "/logout", method = RequestMethod.POST)
    @ResponseBody
    public Object logout(/* HttpSession session */) {
        logger.info("登出");
        //移除加密盐
//        session.removeAttribute("encryption_key");
        Subject subject = SecurityUtils.getSubject();
        subject.logout();
        commonService.clearQueryCache();
        return renderSuccess();
    }

    /**
     * 更新shiro缓存
     *
     * @return
     */
    @ResponseBody
    @RequestMapping("clearAuth")
    public Object clearAuth() {
        ShiroAuthUtil.clearAuth();
        return renderSuccess();
    }

    /**
     * 随机生成6位数字组合作为短信验证码
     *
     * @return
     */
    private String getSMSCode() {
        StringBuffer num = new StringBuffer("0123456789");
        StringBuffer sb = new StringBuffer();
        Random r = new Random();
        for (int i = 0; i < 6; i++) {
            sb.append(num.charAt(r.nextInt(num.length())));
        }
        return sb.toString();
    }


}